import React, { createContext, useContext, useEffect, useState, useCallback } from 'react'
import { User } from '@supabase/supabase-js'
import { supabase, UserAPI, SubscriptionAPI, SessionAPI } from '../lib/supabase'
import { AuthContextType, UserProfile, Subscription, SubscriptionPlan } from '../types/auth'

const AuthContext = createContext<AuthContextType | undefined>(undefined)

export function useAuth() {
  const context = useContext(AuthContext)
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}

interface AuthProviderProps {
  children: React.ReactNode
}

export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<User | null>(null)
  const [userProfile, setUserProfile] = useState<UserProfile | null>(null)
  const [subscription, setSubscription] = useState<Subscription | null>(null)
  const [loading, setLoading] = useState(false)
  const [initializing, setInitializing] = useState(true)

  // Load user data including profile and subscription
  const loadUserData = useCallback(async (user: User | null) => {
    if (!user) {
      setUserProfile(null)
      setSubscription(null)
      return
    }

    setLoading(true)
    try {
      // Load user profile
      const profile = await UserAPI.getUserProfile(user.id)
      setUserProfile(profile)

      // Update last login timestamp
      if (profile) {
        await UserAPI.updateLastLogin(user.id)
      }

      // Load subscription if profile exists
      if (profile) {
        const userSubscription = await SubscriptionAPI.getUserSubscription(user.id)
        setSubscription(userSubscription)
      }
    } catch (error) {
      console.error('Error loading user data:', error)
    } finally {
      setLoading(false)
    }
  }, [])

  // Initialize auth state
  useEffect(() => {
    let mounted = true

    async function initializeAuth() {
      try {
        // Get initial user session
        const { data: { user: initialUser } } = await supabase.auth.getUser()
        
        if (mounted) {
          setUser(initialUser)
          if (initialUser) {
            await loadUserData(initialUser)
          }
        }
      } catch (error) {
        console.error('Error initializing auth:', error)
      } finally {
        if (mounted) {
          setInitializing(false)
        }
      }
    }

    initializeAuth()

    // Set up auth state listener
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      async (event, session) => {
        if (mounted) {
          const currentUser = session?.user || null
          setUser(currentUser)
          
          if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
            await loadUserData(currentUser)
          } else if (event === 'SIGNED_OUT') {
            setUserProfile(null)
            setSubscription(null)
          }
        }
      }
    )

    return () => {
      mounted = false
      subscription.unsubscribe()
    }
  }, [loadUserData])

  // Sign in with email and password
  const signIn = useCallback(async (email: string, password: string, rememberMe = false) => {
    setLoading(true)
    try {
      const { data, error } = await supabase.auth.signInWithPassword({
        email,
        password
      })

      if (error) throw error

      if (data.user && rememberMe) {
        // Create extended session for "remember me"
        await SessionAPI.createSession(data.user.id, navigator.userAgent)
      }
    } catch (error) {
      console.error('Sign in error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [])

  // Sign up with email and password
  const signUp = useCallback(async (
    email: string, 
    password: string, 
    userData?: Partial<UserProfile>
  ) => {
    setLoading(true)
    try {
      const { data, error } = await supabase.auth.signUp({
        email,
        password
      })

      if (error) throw error

      if (data.user) {
        // Create user profile
        await UserAPI.createUserProfile(data.user.id, email, userData)
        
        // Create default free subscription
        await SubscriptionAPI.createSubscription(data.user.id, 'free')
        
        // Reload user data
        await loadUserData(data.user)
      }
    } catch (error) {
      console.error('Sign up error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [loadUserData])

  // Sign out
  const signOut = useCallback(async () => {
    setLoading(true)
    try {
      if (user) {
        // Revoke all sessions
        await SessionAPI.revokeAllUserSessions(user.id)
      }

      const { error } = await supabase.auth.signOut()
      if (error) throw error
    } catch (error) {
      console.error('Sign out error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [user])

  // Reset password
  const resetPassword = useCallback(async (email: string) => {
    setLoading(true)
    try {
      const { error } = await supabase.auth.resetPasswordForEmail(email, {
        redirectTo: `${window.location.origin}/auth/reset-password`
      })
      
      if (error) throw error
    } catch (error) {
      console.error('Reset password error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [])

  // Update password
  const updatePassword = useCallback(async (newPassword: string) => {
    setLoading(true)
    try {
      const { error } = await supabase.auth.updateUser({
        password: newPassword
      })
      
      if (error) throw error
    } catch (error) {
      console.error('Update password error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [])

  // Update user profile
  const updateProfile = useCallback(async (updates: Partial<UserProfile>) => {
    if (!user) throw new Error('No authenticated user')
    
    setLoading(true)
    try {
      // Update auth user metadata if needed
      const authUpdates: any = {}
      if (updates.full_name) authUpdates.full_name = updates.full_name
      if (updates.avatar_url) authUpdates.avatar_url = updates.avatar_url

      if (Object.keys(authUpdates).length > 0) {
        const { error: authError } = await supabase.auth.updateUser(authUpdates)
        if (authError) throw authError
      }

      // Update user profile in database
      const updatedProfile = await UserAPI.updateUserProfile(user.id, updates)
      setUserProfile(updatedProfile)
    } catch (error) {
      console.error('Update profile error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [user])

  // Update subscription
  const updateSubscription = useCallback(async (planType: SubscriptionPlan) => {
    if (!user) throw new Error('No authenticated user')
    
    setLoading(true)
    try {
      // If user has existing subscription, update it
      if (subscription) {
        const updatedSubscription = await SubscriptionAPI.updateSubscription(
          subscription.id,
          { 
            plan_type: planType,
            features: SubscriptionAPI['getPlanFeatures'](planType)
          }
        )
        setSubscription(updatedSubscription)
      } else {
        // Create new subscription
        const newSubscription = await SubscriptionAPI.createSubscription(user.id, planType)
        setSubscription(newSubscription)
      }

      // Update user profile subscription status
      await updateProfile({ 
        subscription_status: planType,
        subscription_start_date: new Date().toISOString()
      })
    } catch (error) {
      console.error('Update subscription error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [user, subscription, updateProfile])

  // Delete user account (GDPR compliance)
  const deleteAccount = useCallback(async () => {
    if (!user) throw new Error('No authenticated user')
    
    setLoading(true)
    try {
      await UserAPI.deleteUserAccount(user.id)
      // Auth state will be updated by the auth listener
    } catch (error) {
      console.error('Delete account error:', error)
      throw error
    } finally {
      setLoading(false)
    }
  }, [user])

  // Refresh user data
  const refreshUserData = useCallback(async () => {
    if (user) {
      await loadUserData(user)
    }
  }, [user, loadUserData])

  // Context value
  const contextValue: AuthContextType = {
    user,
    userProfile,
    subscription,
    loading,
    initializing,
    signIn,
    signUp,
    signOut,
    resetPassword,
    updatePassword,
    updateProfile,
    updateSubscription,
    deleteAccount,
    refreshUserData
  }

  return (
    <AuthContext.Provider value={contextValue}>
      {children}
    </AuthContext.Provider>
  )
}

// Custom hooks for specific auth states
export function useRequireAuth() {
  const { user, initializing } = useAuth()
  
  useEffect(() => {
    if (!initializing && !user) {
      // Redirect to login or show auth modal
      window.location.href = '/auth/login'
    }
  }, [user, initializing])
  
  return { user, isAuthenticated: !!user }
}

export function useSubscription() {
  const { subscription } = useAuth()
  
  const hasFeature = useCallback((feature: keyof Subscription['features']) => {
    if (!subscription) return false
    const featureValue = subscription.features[feature]
    return typeof featureValue === 'boolean' ? featureValue : featureValue > 0
  }, [subscription])
  
  const canUseFeature = useCallback((feature: keyof Subscription['features'], currentUsage = 0) => {
    if (!subscription) return false
    const featureLimit = subscription.features[feature]
    if (typeof featureLimit === 'boolean') return featureLimit
    if (featureLimit === -1) return true // unlimited
    return currentUsage < featureLimit
  }, [subscription])
  
  return {
    subscription,
    hasSubscription: !!subscription,
    isActive: subscription?.status === 'active',
    planType: subscription?.plan_type || 'free',
    hasFeature,
    canUseFeature
  }
}

export function useUserProfile() {
  const { userProfile, updateProfile } = useAuth()
  
  const updatePreferences = useCallback(async (
    type: 'paper' | 'notification' | 'privacy' | 'account',
    preferences: any
  ) => {
    if (!userProfile) return
    
    const updates: Partial<UserProfile> = {}
    switch (type) {
      case 'paper':
        updates.paper_preferences = preferences
        break
      case 'notification':
        updates.notification_preferences = preferences
        break
      case 'privacy':
        updates.privacy_settings = preferences
        break
      case 'account':
        updates.account_settings = preferences
        break
    }
    
    await updateProfile(updates)
  }, [userProfile, updateProfile])
  
  return {
    userProfile,
    updatePreferences,
    hasGdprConsent: userProfile?.gdpr_consent || false,
    isEmailVerified: userProfile?.email_verified || false
  }
}